﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Web.Script.Serialization;
using System.Linq;
using System.Xml.Linq;
using System.Text;
using CookComputing.XmlRpc;
//
using PerceptiveMCAPI.Types.Internal;
using System.IO;

namespace PerceptiveMCAPI.Types
{
   public class getAccountDetailsOutput : Api_BaseOutput
   {
      public getAccountDetailsResults result { get; set; }
      public getAccountDetailsParms inputParms { get; private set; }
      //
      public getAccountDetailsOutput( getAccountDetailsInput input )
         : base( input )
      {
         this.inputParms = input.parms;
         this.result = new getAccountDetailsResults();
      }
      // --------------------------------------------------- tostring
      public override string ToString()
      {
         return string.Format( "{0}", result.username );
      }

      #region ================================================================== format setup

      // ---- serial
      internal void Format( string api_Request, string api_Response )
      {
         this.api_Request = api_Request;
         this.api_Response = api_Response;
         // ----------------------------------
         if ( this.api_OutputType == EnumValues.OutputType.JSON )
            outputJSON();
         else if ( this.api_OutputType == EnumValues.OutputType.XML )
            outputXML();
      }
      // ---- xmlrpc
      internal void Format( x_getAccountDetails rpcResult )
      {
         this.api_Request = EnumValues.NotSupplied;
         this.api_Response = EnumValues.NotSupplied;
         // ------------------------
         this.result = FormatResults( rpcResult );
      }

      #endregion

      #region ================================================================= Output

      // ---------------------------------------------------------- outputJSON
      protected void outputJSON()
      {
         JavaScriptSerializer jss = new JavaScriptSerializer();

         try
         {
            if ( this.api_Response.Contains( EnumValues.JSONErrorString ) )
            {
               Api_Error err = jss.Deserialize<Api_Error>( this.api_Response );
               this.api_ErrorMessages.Add( err );
            }
            else
            {
               Hashtable jsonHash = jss.Deserialize<Hashtable>( this.api_Response );
               x_getAccountDetails jsonResult = FormatHashToXfile( jsonHash );
               this.result = FormatResults( jsonResult );
            }
         }
         catch ( Exception ex )
         {
            this.api_ErrorMessages.Add( apiException.FormatError( ex ) );
         }
      }

      private x_getAccountDetails FormatHashToXfile( Hashtable jsonHash )
      {
         x_getAccountDetails wrk = new x_getAccountDetails();
         //
         IDictionaryEnumerator ide = jsonHash.GetEnumerator();
         while ( ide.MoveNext() )
         {
            if ( ide.Entry.Key.ToString() == "user_id" ) wrk.user_id = ide.Entry.Value.ToString() ?? "";
            if ( ide.Entry.Key.ToString() == "username" ) wrk.username = ide.Entry.Value.ToString() ?? "";
            if ( ide.Entry.Key.ToString() == "member_since" ) wrk.member_since = ide.Entry.Value.ToString() ?? "";
            if ( ide.Entry.Key.ToString() == "is_approved" ) wrk.is_approved = (bool)ide.Entry.Value;
            if ( ide.Entry.Key.ToString() == "is_trial" ) wrk.is_trial = (bool)ide.Entry.Value;
            if ( ide.Entry.Key.ToString() == "timezone" ) wrk.timezone = ide.Entry.Value.ToString() ?? "";
            if ( ide.Entry.Key.ToString() == "plan_type" ) wrk.plan_type = ide.Entry.Value.ToString() ?? "";
            if ( ide.Entry.Key.ToString() == "plan_low" ) wrk.plan_low = (int)ide.Entry.Value;
            if ( ide.Entry.Key.ToString() == "plan_high" ) wrk.plan_high = (int)ide.Entry.Value;
            if ( ide.Entry.Key.ToString() == "plan_start_date" ) wrk.plan_start_date = ide.Entry.Value.ToString() ?? "";
            if ( ide.Entry.Key.ToString() == "emails_left" ) wrk.emails_left = (int)ide.Entry.Value;
            if ( ide.Entry.Key.ToString() == "pending_monthly" ) wrk.pending_monthly = (bool)ide.Entry.Value;
            if ( ide.Entry.Key.ToString() == "first_payment" ) wrk.first_payment = string.Format( "{0}", ide.Entry.Value );
            if ( ide.Entry.Key.ToString() == "last_payment" ) wrk.last_payment = string.Format( "{0}", ide.Entry.Value );
            if ( ide.Entry.Key.ToString() == "times_logged_in" ) wrk.times_logged_in = (int)ide.Entry.Value;
            if ( ide.Entry.Key.ToString() == "last_login" ) wrk.last_login = ide.Entry.Value.ToString() ?? "";
            if ( ide.Entry.Key.ToString() == "affiliate_link" ) wrk.affiliate_link = ide.Entry.Value.ToString() ?? "";
            if ( ide.Entry.Key.ToString() == "contact" ) wrk.contact = ide.Entry.Value;
            if ( ide.Entry.Key.ToString() == "modules" ) wrk.modules = ide.Entry.Value;
            if ( ide.Entry.Key.ToString() == "orders" ) wrk.orders = ide.Entry.Value;
            if ( ide.Entry.Key.ToString() == "rewards" ) wrk.rewards = ide.Entry.Value;
         }
         return wrk;
      }
      // ---------------------------------------------------------- outputXML
      protected void outputXML()
      {
         XElement xml = XElement.Parse( this.api_Response );
         // error check
         Api_Error error = apiSerial.GetXmlOutputError( xml );
         if ( error != null )
         {
            this.api_ErrorMessages.Add( error );
            return;
         }
         // -------------------------------------------- get values
         try
         {
            DateTime dt; int it; double dbl;
            getAccountDetailsResults acct = new getAccountDetailsResults();
            XElement root = xml;
            //
            acct.user_id = root.Element( "user_id" ).Value;
            acct.username = root.Element( "username" ).Value;
            DateTime.TryParse( root.Element( "member_since" ).Value, out dt );
            acct.member_since = dt;
            acct.is_approved = ( root.Element( "is_approved" ).Value.Trim() == "1" ) ? true : false;
            acct.is_trial = ( root.Element( "is_trial" ).Value.Trim() == "1" ) ? true : false;
            acct.timezone = root.Element( "timezone" ).Value;
            acct.plan_type = root.Element( "plan_type" ).Value;
            int.TryParse( root.Element( "emails_left" ).Value, out it );
            acct.emails_left = it;
            acct.pending_monthly = ( root.Element( "pending_monthly" ).Value.Trim() == "1" ) ? true : false;
            DateTime.TryParse( root.Element( "first_payment" ).Value, out dt );
            acct.first_payment = dt;
            DateTime.TryParse( root.Element( "last_payment" ).Value, out dt );
            acct.last_payment = dt;
            int.TryParse( root.Element( "times_logged_in" ).Value, out it );
            acct.times_logged_in = it;
            DateTime.TryParse( root.Element( "last_login" ).Value, out dt );
            acct.last_login = dt;
            acct.affiliate_link = root.Element( "affiliate_link" ).Value;
            // contact
            XElement ctcInfo = root.Element( "contact" );
            acct.contact.fname = ctcInfo.Element( "fname" ).Value;
            acct.contact.lname = ctcInfo.Element( "lname" ).Value;
            acct.contact.company = ctcInfo.Element( "company" ).Value;
            acct.contact.address1 = ctcInfo.Element( "address1" ).Value;
            acct.contact.address2 = ctcInfo.Element( "address2" ).Value;
            acct.contact.city = ctcInfo.Element( "city" ).Value;
            acct.contact.state = ctcInfo.Element( "state" ).Value;
            acct.contact.zip = ctcInfo.Element( "zip" ).Value;
            acct.contact.country = ctcInfo.Element( "country" ).Value;
            acct.contact.email = ctcInfo.Element( "email" ).Value;
            acct.contact.url = ctcInfo.Element( "url" ).Value;
            // modules
            XElement moduleArray = root.Element( "modules" );
            if ( moduleArray.HasElements )
            {
               IEnumerable<XElement> modules = moduleArray.Elements( "struct" );
               foreach ( XElement module in modules )
               {
                  string name = module.Element( "name" ).Value;
                  DateTime.TryParse( module.Element( "added" ).Value, out dt );
                  acct.modules.Add( new getAccountDetails_module { name = name, added = dt } );
               }
            }
            // orders
            XElement orderArray = root.Element( "orders" );
            if ( orderArray.HasElements )
            {
               float fl = 0;
               IEnumerable<XElement> orders = orderArray.Elements( "struct" );
               foreach ( XElement order in orders )
               {
                  getAccountDetails_order ord = new getAccountDetails_order();

                  int.TryParse( order.Element( "order_id" ).Value, out it );
                  ord.order_id = it;

                  ord.type = order.Element( "type" ).Value;

                  if ( !order.Element( "amount" ).IsEmpty )
                  { float.TryParse( order.Element( "amount" ).Value, out fl ); }
                  ord.amount = fl;

                  if ( !order.Element( "date" ).IsEmpty )
                  {
                     DateTime.TryParse( order.Element( "date" ).Value, out dt );
                     ord.order_date = dt;
                  }
                  else
                  { ord.order_date = DateTime.MinValue; }

                  ord.credits_user = order.Element( "credits_user" ).Value;
                  //
                  acct.orders.Add( ord );
               }
            }
            // rewards
            XElement rewardsArray = root.Element( "rewards" );
            if ( rewardsArray.HasElements )
            {
               int.TryParse( rewardsArray.Element( "referals_this_month" ).Value, out it );
               acct.rewards.referals_this_month = it;
               acct.rewards.notify_on = ( rewardsArray.Element( "notify_on" ).Value.Trim() == "1" ) ? true : false;
               acct.rewards.notify_email = rewardsArray.Element( "notify_email" ).Value ?? "";
               // credits
               if ( rewardsArray.Element( "credits" ).HasElements )
               {
                  XElement credits_array = rewardsArray.Element( "credits" );
                  double.TryParse( credits_array.Element( "this_month" ).Value, out dbl );
                  acct.rewards.credits.this_month = dbl;
                  double.TryParse( credits_array.Element( "total_earned" ).Value, out dbl );
                  acct.rewards.credits.total_earned = dbl;
                  double.TryParse( credits_array.Element( "remaining" ).Value, out dbl );
                  acct.rewards.credits.remaining = dbl;
               }
               // inspections
               if ( rewardsArray.Element( "inspections" ).HasElements )
               {
                  XElement inspect_array = rewardsArray.Element( "inspections" );
                  double.TryParse( inspect_array.Element( "this_month" ).Value, out dbl );
                  acct.rewards.inspections.this_month = dbl;
                  double.TryParse( inspect_array.Element( "total_earned" ).Value, out dbl );
                  acct.rewards.inspections.total_earned = dbl;
                  double.TryParse( inspect_array.Element( "remaining" ).Value, out dbl );
                  acct.rewards.inspections.remaining = dbl;
               }
               // referrals
               if ( rewardsArray.Element( "referrals" ).HasElements )
               {
                  IEnumerable<XElement> referrals_array = rewardsArray.Element( "referrals" ).Descendants( "struct" );

                  foreach ( XElement refer_struct in referrals_array )
                  {
                     getAccountDetails_rewards.reward_referral referral = new getAccountDetails_rewards.reward_referral();
                     referral.name = refer_struct.Element( "name" ).Value ?? "";
                     referral.email = refer_struct.Element( "email" ).Value ?? "";
                     DateTime.TryParse( refer_struct.Element( "signup_date" ).Value, out dt );
                     referral.signup_date = dt;
                     referral.type = refer_struct.Element( "type" ).Value ?? "";
                     acct.rewards.referrals.Add( referral );
                  }
               }
               // applied
               if ( rewardsArray.Element( "applied" ).HasElements )
               {
                  // --- TODO: No sample yet to see how this is structured....
               }
            }
            // ----------------------
            this.result = acct;
         }
         catch ( Exception ex )
         {
            this.api_ErrorMessages.Add( apiException.FormatError( ex ) );
         }
      }

      // ---------------------------------------------------------- Formatting
      private getAccountDetailsResults FormatResults( x_getAccountDetails x_results )
      {
         DateTime dt;
         getAccountDetailsResults result = new getAccountDetailsResults();
         result.user_id = x_results.user_id;
         result.username = x_results.username;
         DateTime.TryParse( x_results.member_since, out dt );
         result.member_since = dt;
         result.is_approved = x_results.is_approved;
         result.is_trial = x_results.is_trial;
         result.timezone = x_results.timezone;
         result.plan_type = x_results.plan_type;
         result.plan_low = x_results.plan_low;
         result.plan_high = x_results.plan_high;
         DateTime.TryParse( x_results.plan_start_date, out dt );
         result.plan_start_date = dt;
         result.emails_left = x_results.emails_left;
         result.pending_monthly = x_results.pending_monthly;
         DateTime.TryParse( x_results.first_payment, out dt );
         result.first_payment = dt;
         DateTime.TryParse( x_results.last_payment, out dt );
         result.last_payment = dt;
         result.times_logged_in = x_results.times_logged_in;
         DateTime.TryParse( x_results.last_login, out dt );
         result.last_login = dt;
         result.affiliate_link = x_results.affiliate_link;
         // ----------------------------------------------------- contact, modules, orders , rewards
         result.contact = FormatContact( x_results.contact );
         result.modules = FormatModules( x_results.modules );
         result.orders = FormatOrders( x_results.orders );
         result.rewards = FormatRewards( x_results.rewards );

         return result;
      }

      private getAccountDetails_contact FormatContact( object contact_struct )
      {
         getAccountDetails_contact contact = new getAccountDetails_contact();
         IDictionary ctc = contact_struct as IDictionary;
         // ---------------
         // contact info
         // ---------------
         contact.fname = ctc["fname"].ToString();
         contact.lname = ctc["lname"].ToString();
         contact.email = ctc["email"].ToString();
         contact.company = ctc["company"].ToString();
         contact.address1 = ctc["address1"].ToString();
         contact.address2 = ctc["address2"].ToString();
         contact.city = ctc["city"].ToString();
         contact.state = ctc["state"].ToString();
         contact.zip = ctc["zip"].ToString();
         contact.country = ctc["country"].ToString();
         contact.url = ctc["url"].ToString();
         //
         return contact;
      }

      private List<getAccountDetails_module> FormatModules( object modulesObject )
      {
         DateTime dt;
         List<getAccountDetails_module> modules = new List<getAccountDetails_module>();
         object[] modulesArray = modulesObject as object[];

         foreach ( object obj in modulesArray )
         {
            getAccountDetails_module acctModule = new getAccountDetails_module();
            IDictionary mod = obj as IDictionary;
            acctModule.name = mod["name"].ToString();
            DateTime.TryParse( mod["added"].ToString(), out dt );
            acctModule.added = dt;
            //
            modules.Add( acctModule );
         }
         return modules;
      }

      private List<getAccountDetails_order> FormatOrders( object ordersObject )
      {
         int it; DateTime dt; float fl;
         List<getAccountDetails_order> orders = new List<getAccountDetails_order>();
         object[] ordersArray = ordersObject as object[];

         foreach ( object obj in ordersArray )
         {
            getAccountDetails_order acctOrder = new getAccountDetails_order();
            IDictionary ord = obj as IDictionary;
            //----------------------------------------------------------------
            int.TryParse( ord["order_id"].ToString(), out it );
            acctOrder.order_id = it;
            acctOrder.type = ord["type"].ToString();
            if ( apiHelper.IsNumeric( ord["amount"].ToString() ) )
            {
               float.TryParse( ord["amount"].ToString(), out fl );
               acctOrder.amount = fl;
            }
            if ( ord["date"] != null )
            {
               DateTime.TryParse( ord["date"].ToString(), out dt );
               acctOrder.order_date = dt;
            }
            if ( ord["credits_user"] != null )
            {
               acctOrder.credits_user = ord["credits_user"].ToString();
            }

            orders.Add( acctOrder );
         }
         return orders;
      }

      private getAccountDetails_rewards FormatRewards( object rewardsObject )
      {
         int it; bool bt;
         getAccountDetails_rewards rewards = new getAccountDetails_rewards();

         //--------------------------------------------------------
         IDictionary reward = rewardsObject as IDictionary;
         int.TryParse( reward["referals_this_month"].ToString(), out it );
         rewards.referals_this_month = it;

         bool.TryParse( reward["notify_on"].ToString(), out bt );
         rewards.notify_on = bt;

         if ( reward["notify_email"] != null )
            rewards.notify_email = reward["notify_email"].ToString() ?? string.Empty;

         if ( reward["credits"] != null )
         {
            IDictionary reward_credits = reward["credits"] as IDictionary;
            rewards.credits = getCredits( reward_credits );
         }

         if ( reward["inspections"] != null )
         {
            IDictionary reward_inspect = reward["inspections"] as IDictionary;
            rewards.inspections = getInspections( reward_inspect );
         }

         if ( reward["referrals"] != null )
         {
            object[] reward_referrals = reward["referrals"] as object[];
            rewards.referrals = getReferrals( reward_referrals );
         }

         if ( reward["applied"] != null )
         {
            object[] reward_applied = reward["applied"] as object[];
            rewards.applied = getApplied( reward_applied );
         }

         return rewards;
      }

      private getAccountDetails_rewards.reward_credits getCredits( IDictionary credit_struct )
      {
         double dbl;
         getAccountDetails_rewards.reward_credits credits = new getAccountDetails_rewards.reward_credits();

         double.TryParse( credit_struct["this_month"].ToString(), out dbl );
         credits.this_month = dbl;
         double.TryParse( credit_struct["total_earned"].ToString(), out dbl );
         credits.total_earned = dbl;
         double.TryParse( credit_struct["remaining"].ToString(), out dbl );
         credits.remaining = dbl;
         //
         return credits;
      }

      private getAccountDetails_rewards.reward_inspections getInspections( IDictionary inspect_struct )
      {
         double dbl;
         getAccountDetails_rewards.reward_inspections inspects = new getAccountDetails_rewards.reward_inspections();
         double.TryParse( inspect_struct["this_month"].ToString(), out dbl );
         inspects.this_month = dbl;
         double.TryParse( inspect_struct["total_earned"].ToString(), out dbl );
         inspects.total_earned = dbl;
         double.TryParse( inspect_struct["remaining"].ToString(), out dbl );
         inspects.remaining = dbl;
         //
         return inspects;
      }

      private List<getAccountDetails_rewards.reward_referral> getReferrals( object[] referrals_struct )
      {
         DateTime dt;
         List<getAccountDetails_rewards.reward_referral> referrals = new List<getAccountDetails_rewards.reward_referral>();
         foreach ( object referral_obj in referrals_struct )
         {
            getAccountDetails_rewards.reward_referral referral = new getAccountDetails_rewards.reward_referral();
            IDictionary dict = referral_obj as IDictionary;
            if ( dict["name"] != null )
               referral.name = dict["name"].ToString();
            if ( dict["email"] != null )
               referral.email = dict["email"].ToString();
            if ( dict["signup_date"] != null )
            {
               DateTime.TryParse( dict["signup_date"].ToString(), out dt );
               referral.signup_date = dt;
            }
            if ( dict["type"] != null )
               referral.type = dict["type"].ToString();
            //
            referrals.Add( referral );
         }
         //
         return referrals;
      }

      private List<getAccountDetails_rewards.reward_applied> getApplied( object[] applied_struct )
      {
         // DateTime dt;
         List<getAccountDetails_rewards.reward_applied> applieds = new List<getAccountDetails_rewards.reward_applied>();
         foreach ( object applied_obj in applied_struct )
         {
            getAccountDetails_rewards.reward_applied applied = new getAccountDetails_rewards.reward_applied();
            IDictionary dict = applied_obj as IDictionary;
            //
            // TODO: get structure and implement
            //
            // applieds.Add( applied );
         }
         //
         return applieds;
      }

      #endregion
   }
}
